#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>

int main(){

    int n = 100; //numero maximo de threads

    omp_set_num_threads(n); //define o numero maximo de threads

    FILE *f;
    int i, tam=0, inicio, fim, cont=0, tam_frase, pos_anterior, pos_atual, n_caracteres_txt, aux, inicio_trecho[n+1];
    char *texto, c, *frase;

    f = fopen("shakespe.txt", "r");

    fseek(f, 0, SEEK_END); //posiciona o cursor no fim do arquivo

    n_caracteres_txt = ftell(f); //a ultima posicao do arquivo é igual ao numero de caracteres no txt

    for(i=0;i<n;i++)
        inicio_trecho[i] = i*((int) n_caracteres_txt / n); //dividindo o txt em n partes

    for(i=1;i<n;i++){ //para a segunda thread até a ultima
        fseek(f, inicio_trecho[i], SEEK_SET);  //posiciona o cursor no começo do trecho da thread
        c = fgetc(f);  //retorna o primeiro caracter do trecho da thread
        while(c != '\n' && c != '\r' && c != '.' && c != '?' && c != '!') //se for letra ou numero, ou seja, esta no meio da palavra
            c = fgetc(f);  //avança para o proximo, até que nao seja mais uma letra ou numero
        inicio_trecho[i] = ftell(f); //o inicio do trecho da thread é definido
    }

    texto = (char *) malloc(n_caracteres_txt*sizeof(char)); //alocando memoria para o numero total de caracteres do txt

    if(texto == NULL) {
            printf("Malloc devolveu NULL!\n");
            exit(1);
    }

    fseek(f, 0, SEEK_SET); //posiciona o cursor no inicio do txt
    for(i=0;i<n_caracteres_txt;i++) //para o primeiro caracter do txt, até o ultimo
        texto[i] = fgetc(f); //copia o caracter para a memoria

    fclose(f);
    inicio_trecho[n] = n_caracteres_txt+1; //o fim do ultimo trecho é o inicio do proximo que não existe, ou seja, é o fim do txt

    #pragma omp parallel firstprivate(inicio_trecho, texto) private(i, tam, tam_frase, inicio, fim, c, frase, pos_anterior, pos_atual, aux) shared(cont)
    {
        pos_anterior = inicio_trecho[omp_get_thread_num()]; //pos_atual recebe o inicio de cada thread
        //printf("Thread %d começou!!!!!!!!!!!!\n", omp_get_thread_num());

        while(1){
            tam_frase = 0;
            pos_atual = pos_anterior; //a posicao atual, é o inicio de cada frase, que é o fim da frase anterior

            c = ' ';
            while(c != '\n' && c != '\r' && c != '.' && c != '?' && c != '!'){  //enquanto o caracter não for fim de uma frase(\r, ".", "?", "!" ou fim do txt
                c = texto[pos_atual];  //pega o proxima
                if((c >= 48 && c <= 57) || (c >= 65 && c<= 90) || (c >= 97 && c<= 122)){ //se for letra(maiuscula ou minuscula) ou numero
                    tam_frase++;   //incrementa o tamanho da frase a ser analisada
                }
                pos_atual++;
            }

            aux = pos_atual;  //guarda a "pos_atual" numa variavel auxiliar
            pos_atual = pos_anterior; //guarda em "pos_atual" a posicao anterior no texto. para analisar a frase
            pos_anterior = aux; //guarda em "pos_anterior" a posicao atual no texto

            frase = (char *) malloc(tam_frase*sizeof(char)); //aloca "tam_frase" posições na memoria, para salvar toda a frase

            if(frase == NULL) {
                printf("Malloc devolveu NULL!\n");
                exit(1);
            }

            tam = 0;
            while(1){
                c = texto[pos_atual]; //pega proximo caracter
                //printf("Sou a thread %d na posicao %d e com o caracter %c \n", omp_get_thread_num(), pos_atual, c);

                if((c >= 48 && c <= 57) || (c >= 65 && c<= 90) || (c >= 97 && c<= 122)){ //se for letra(maiuscula ou minuscula) ou numero
                    frase[tam] = c; //adiciona o caracter ao vetor palavra
                    tam++;  //tamanho do vetor é incrementado
                }

                else if(c == '\n' || c == '\r' || c == '.' || c == '!' || c == '?' || pos_atual == n_caracteres_txt){ //se o caracter representar fim de uma frase ou fim do txt
                    if(frase != NULL){  //se já tem algum caracter no vetor frase, vai ser analisada a ocorrencia de palindromo
                        inicio = 0;   //inicio da frase
                        fim = tam-1; //a iteração do for a seguir decrementada

                        if(tam % 2 == 1)  //se a frase tem numero impar de letras
                            tam = tam-1; //a iteração do for a seguir decrementada

                        for(inicio; inicio<(tam/2);){
                            if(frase[inicio] != frase[fim])  //se a primeira e ultima letra forem diferentes, nao é palindromo. O mesmo é verificado para as proximas letras
                                break;
                            else{
                                if(inicio == (tam/2)-1){ //se chegar ao meio da frase, quer dizer que é um palindromo
                                    //printf("\nPALINDROMO!!!!   >>>>   %s", frase);
                                    cont++; //contador de palindromos
                                }
                            }
                            inicio++; //incrementa a primeira letra
                            fim--;   //decrementa a ultima letra
                        }
                    }
                    pos_atual++;//incrementa a pos_atual para pegar o proximo caracter
                    break; //sai do while, para analisar a proxima frase
                }
                pos_atual++;//incrementa a pos_atual para pegar o proximo caracter
            }
            free(frase); //liberando o que foi alocado na memoria
            if(pos_atual == inicio_trecho[omp_get_thread_num()+1]) //se o ultimo caracter lido for EOF
                break;   //sai do while principal e termina o programa
        }
        //printf("Thread %d terminou!!!\n", omp_get_thread_num());
    }
    free(texto);
    printf("\nNumero de Palindromos encontrados: %d\n", cont);
    return 0;
}
